#ifndef __POPUP_SSL_HPP__
#define __POPUP_SSL_HPP__

#include <openssl/rsa.h>
#include <openssl/blowfish.h>
#include <PopupLoggerUI.hpp>

namespace Popup
{
  enum SslContextType { CLIENT_CONTEXT, SERVER_CONTEXT };
  typedef unsigned char BlowfishKey[128];


  struct BlowfishHelper
  {
    BlowfishHelper(SslContextType ctxt);
    ~BlowfishHelper() {}

    void setKey(const BlowfishKey & p_key);
    const BlowfishKey & getKey() const;
    bool encrypt(unsigned char *p_buffOut, const unsigned char *p_buffIn,
                 size_t p_size) const;
    bool decrypt(unsigned char *p_buffOut, const unsigned char *p_buffIn,
                 size_t p_size) const;

  private:
    BF_KEY key;
    BlowfishKey seed;
  };

  struct RSAHelper
  {
  private:

    enum RSAHelperMode
    {
      RSA_MASTER,
      RSA_SLAVE
    };

    RSA *key;
    BIGNUM *num;
    enum RSAHelperMode mode;
    unsigned char *rawpubkey;
    size_t rawpubkeySize;

  public:
    //! Creates a new RSA context (private/public)
    RSAHelper();
    //! Creates a new RSA context (public only)
    RSAHelper(const unsigned char *p_publicKey, size_t p_keySize);
    ~RSAHelper();

    //! Returns the public key raw buffer
    size_t getRawPublicKey(const unsigned char **p_key) const;

    //! Encrypts the given buffer to the output buffer
    //! \return  true upon success
    //!          false othewise (eg. not enough space in output buffer);
    bool encrypt(const unsigned char *p_buffIn, size_t p_sizeIn,
                 unsigned char *p_buffOut, size_t *p_sizeOut) const;

    bool decrypt(const unsigned char *p_buffIn, size_t p_sizeIn,
                 unsigned char *p_buffOut, size_t *p_sizeOut) const;
  };

  struct SslContext
  {
    SslContext(SslContextType ctxtType);
    SslContext(SslContextType ctxtType, RSAHelper *p_localRsaHelper);
    ~SslContext();

    //! Returns the public key raw buffer
    size_t getLocalRSApublicKey(const unsigned char **p_key) const;

    const BlowfishKey & getBlowfishKey() const;

    void setRemoteRSApublicKey(const unsigned char *p_key, size_t p_size);

    void setRemoteBlowfishKey(const BlowfishKey & p_key);

    bool blowfishEncrypt(void *p_out, size_t p_size) const;
    bool blowfishDecrypt(void *p_out, size_t p_size) const;

    bool blowfishEncrypt(void *p_out, const void *p_in,
                         size_t p_size) const;
    bool blowfishDecrypt(void *p_out, const void *p_in,
                         size_t p_size) const;

    bool rsaEncrypt(void *p_out, size_t *p_sizeOut,
                    const void *p_in, size_t p_sizeIn) const;
    bool rsaDecrypt(void *p_out, size_t *p_sizeOut,
                    const void *p_in, size_t p_sizeIn) const;

    RSAHelper *rsaLocal;
    RSAHelper *rsaRemote;
    bool deleteRsaLocal;
    BlowfishHelper blowfish;

  };
}

#endif
